"""
Loguru中间件
为FastAPI提供企业级的HTTP请求日志记录
"""

import time
import uuid
from datetime import datetime
from typing import Callable, List, Dict, Optional, Any
from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.types import ASGIApp

from app.core.loguru_config import get_loguru_config, log_info, log_error


class LoguruMiddleware(BaseHTTPMiddleware):
    """Loguru日志中间件"""
    
    def __init__(self, app: ASGIApp, 
                 log_requests: bool = True,
                 log_responses: bool = True,
                 exclude_paths: Optional[List[str]] = None):
        super().__init__(app)
        self.log_requests = log_requests
        self.log_responses = log_responses
        self.exclude_paths = exclude_paths or []
        # 延迟初始化配置，在dispatch中获取
        self.config = None
        self.initialized = False
    
    async def dispatch(self, request: Request, call_next: Callable) -> Response:
        """处理HTTP请求"""
        
        # 检查是否应该排除此路径
        if self._should_exclude_path(request.url.path):
            return await call_next(request)
        
        # 获取配置（延迟初始化）
        if self.config is None:
            try:
                self.config = get_loguru_config()
                self.initialized = True
            except RuntimeError:
                # 如果配置尚未初始化，跳过日志记录
                return await call_next(request)
        
        # 如果配置仍未初始化，跳过日志记录
        if not self.initialized:
            return await call_next(request)
        
        # 生成请求ID
        request_id = str(uuid.uuid4())
        user_id = self._get_user_id_from_request(request)
        
        # 设置请求上下文
        self.config.set_request_context(request_id=request_id, user_id=user_id)
        
        # 记录请求开始
        start_time = time.time()
        
        try:
            # 记录请求信息
            if self.log_requests:
                await self._log_request(request, request_id, user_id)
            
            # 处理请求
            response = await call_next(request)
            
            # 记录响应信息
            if self.log_responses:
                await self._log_response(request, response, start_time, request_id)
            
            return response
            
        except Exception as e:
            # 记录异常信息
            await self._log_exception(request, e, start_time, request_id)
            raise
    
    def _should_exclude_path(self, path: str) -> bool:
        """检查是否应该排除此路径"""
        for exclude_path in self.exclude_paths:
            if path.startswith(exclude_path):
                return True
        return False
    
    def _get_user_id_from_request(self, request: Request) -> str:
        """从请求中获取用户ID"""
        # 这里可以从JWT令牌、Session等获取用户ID
        # 实际项目中可以根据需要实现
        
        # 示例：从认证头中获取
        auth_header = request.headers.get("Authorization")
        if auth_header and auth_header.startswith("Bearer "):
            # 在实际项目中，这里可以解析JWT令牌获取用户ID
            return "authenticated-user"
        
        return "anonymous"
    
    async def _log_request(self, request: Request, request_id: str, user_id: str):
        """记录请求日志"""
        request_body = await self._get_request_body(request)
        
        log_info(
            "HTTP请求开始",
            request_id=request_id,
            user_id=user_id,
            method=request.method,
            url=str(request.url),
            client_ip=request.client.host if request.client else "unknown",
            user_agent=request.headers.get("user-agent", ""),
            content_length=request.headers.get("content-length", "0"),
            content_type=request.headers.get("content-type", ""),
            request_body_size=len(request_body) if request_body else 0
        )
    
    async def _log_response(self, request: Request, response: Response, 
                           start_time: float, request_id: str):
        """记录响应日志"""
        duration_ms = (time.time() - start_time) * 1000
        
        log_info(
            "HTTP请求完成",
            request_id=request_id,
            method=request.method,
            url=str(request.url),
            status_code=response.status_code,
            duration_ms=round(duration_ms, 2),
            response_size=response.headers.get("content-length", "0"),
            content_type=response.headers.get("content-type", "")
        )
    
    async def _log_exception(self, request: Request, exception: Exception, 
                            start_time: float, request_id: str):
        """记录异常日志"""
        duration_ms = (time.time() - start_time) * 1000
        
        log_error(
            "HTTP请求异常",
            request_id=request_id,
            method=request.method,
            url=str(request.url),
            exception_type=type(exception).__name__,
            exception_message=str(exception),
            duration_ms=round(duration_ms, 2)
        )
    
    async def _get_request_body(self, request: Request) -> str:
        """获取请求体（用于调试）"""
        try:
            # 只记录小请求体，避免日志过大
            content_length = request.headers.get("content-length")
            if content_length and int(content_length) > 1024:  # 1KB限制
                return "[body too large]"
            
            body = await request.body()
            if body:
                return body.decode("utf-8", errors="ignore")
            return ""
        except Exception:
            return "[unable to read body]"


class APILoggingMiddleware(BaseHTTPMiddleware):
    """API专用日志中间件"""
    
    def __init__(self, app: ASGIApp):
        super().__init__(app)
        # 延迟初始化配置，在dispatch中获取
        self.config = None
        self.initialized = False
    
    async def dispatch(self, request: Request, call_next: Callable) -> Response:
        """处理API请求"""
        
        # 只记录API路径
        if not request.url.path.startswith("/api"):
            return await call_next(request)
        
        # 获取配置（延迟初始化）
        if self.config is None:
            try:
                self.config = get_loguru_config()
                self.initialized = True
            except RuntimeError:
                # 如果配置尚未初始化，跳过日志记录
                return await call_next(request)
        
        # 如果配置仍未初始化，跳过日志记录
        if not self.initialized:
            return await call_next(request)
        
        # 生成请求ID
        request_id = str(uuid.uuid4())
        
        # 设置请求上下文
        self.config.set_request_context(request_id=request_id)
        
        # 记录API请求开始
        start_time = time.time()
        
        try:
            # 记录API请求
            await self._log_api_request(request, request_id)
            
            # 处理请求
            response = await call_next(request)
            
            # 记录API响应
            await self._log_api_response(request, response, start_time, request_id)
            
            return response
            
        except Exception as e:
            # 记录API异常
            await self._log_api_exception(request, e, start_time, request_id)
            raise
    
    async def _log_api_request(self, request: Request, request_id: str):
        """记录API请求"""
        log_info(
            "API请求",
            request_id=request_id,
            api_path=request.url.path,
            method=request.method,
            client_ip=request.client.host if request.client else "unknown",
            user_agent=request.headers.get("user-agent", ""),
            query_params=dict(request.query_params)
        )
    
    async def _log_api_response(self, request: Request, response: Response, 
                               start_time: float, request_id: str):
        """记录API响应"""
        duration_ms = (time.time() - start_time) * 1000
        
        log_info(
            "API响应",
            request_id=request_id,
            api_path=request.url.path,
            method=request.method,
            status_code=response.status_code,
            duration_ms=round(duration_ms, 2)
        )
    
    async def _log_api_exception(self, request: Request, exception: Exception, 
                                start_time: float, request_id: str):
        """记录API异常"""
        duration_ms = (time.time() - start_time) * 1000
        
        log_error(
            "API异常",
            request_id=request_id,
            api_path=request.url.path,
            method=request.method,
            exception_type=type(exception).__name__,
            exception_message=str(exception),
            duration_ms=round(duration_ms, 2)
        )


class DatabaseLoggingMiddleware:
    """数据库操作日志中间件"""
    
    def __init__(self):
        # 延迟初始化配置
        self.config = None
        self.initialized = False
    
    def _get_config(self):
        """获取配置（延迟初始化）"""
        if self.config is None:
            try:
                self.config = get_loguru_config()
                self.initialized = True
            except RuntimeError:
                # 如果配置尚未初始化，返回None
                return None
        return self.config
    
    def log_query(self, query: str, parameters: Optional[Dict[str, Any]] = None, 
                  duration_ms: Optional[float] = None, success: bool = True):
        """记录数据库查询日志"""
        config = self._get_config()
        if config is None or not self.initialized:
            return  # 跳过日志记录
            
        if duration_ms is None:
            duration_ms = 0.0
        
        log_info(
            "数据库查询",
            operation="query",
            query=query[:200] + "..." if len(query) > 200 else query,  # 限制长度
            parameters=parameters,
            duration_ms=round(duration_ms, 2),
            success=success
        )
    
    def log_transaction(self, operation: str, table: str = "", 
                       duration_ms: Optional[float] = None, success: bool = True):
        """记录数据库事务日志"""
        config = self._get_config()
        if config is None or not self.initialized:
            return  # 跳过日志记录
            
        if duration_ms is None:
            duration_ms = 0.0
        
        log_info(
            "数据库事务",
            operation=operation,
            table=table,
            duration_ms=round(duration_ms, 2),
            success=success
        )
    
    def log_error(self, operation: str, error: str, query: str = ""):
        """记录数据库错误日志"""
        config = self._get_config()
        if config is None or not self.initialized:
            return  # 跳过日志记录
            
        log_error(
            "数据库错误",
            operation=operation,
            error=error,
            query=query[:200] + "..." if len(query) > 200 else query
        )


class PerformanceMonitoringMiddleware:
    """性能监控中间件"""
    
    def __init__(self):
        # 延迟初始化配置
        self.config = None
        self.initialized = False
    
    def _get_config(self):
        """获取配置（延迟初始化）"""
        if self.config is None:
            try:
                self.config = get_loguru_config()
                self.initialized = True
            except RuntimeError:
                # 如果配置尚未初始化，返回None
                return None
        return self.config
    
    def start_timer(self, operation: str) -> float:
        """开始计时"""
        return time.time()
    
    def end_timer(self, start_time: float, operation: str, 
                 resource: str = "", success: bool = True):
        """结束计时并记录性能日志"""
        config = self._get_config()
        if config is None or not self.initialized:
            return  # 跳过日志记录
            
        duration_ms = (time.time() - start_time) * 1000
        
        from app.core.loguru_config import log_performance
        log_performance(
            operation=operation,
            duration_ms=round(duration_ms, 2),
            resource=resource,
            status="success" if success else "error"
        )
        
        return duration_ms


# 中间件配置函数
def setup_loguru_middleware(app: ASGIApp) -> ASGIApp:
    """设置Loguru中间件"""
    
    # 排除的健康检查路径
    exclude_paths = ["/health", "/favicon.ico", "/docs", "/redoc", "/openapi.json"]
    
    # 添加Loguru中间件
    app.add_middleware(
        LoguruMiddleware,
        log_requests=True,
        log_responses=True,
        exclude_paths=exclude_paths
    )
    
    # 添加API专用日志中间件
    app.add_middleware(APILoggingMiddleware)
    
    return app


# 便捷函数
def get_request_logger():
    """获取请求日志记录器"""
    try:
        config = get_loguru_config()
        return config.bind_context(**config.get_context_bindings())
    except RuntimeError:
        # 如果配置尚未初始化，返回None或默认记录器
        return None


def log_business_operation(operation: str, details: Optional[Dict[str, Any]] = None, 
                         user_id: str = "", success: bool = True):
    """记录业务操作日志"""
    if details is None:
        details = {}
    
    try:
        log_info(
            "业务操作",
            operation=operation,
            user_id=user_id,
            success=success,
            **details
        )
    except RuntimeError:
        # 如果配置尚未初始化，跳过日志记录
        pass


if __name__ == "__main__":
    # 测试中间件功能
    import asyncio